package com.deimos.dataBase;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.SQLQuery;

import org.hibernate.classic.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.vast.util.DateTime;

import com.deimos.Notification;
import com.deimos.UtilsDeimos;
import com.deimos.dataBase.utils.HibernateUtil;

import org.vast.ows.OWSException;
import org.vast.ows.sps.StatusReport;
import org.vast.ows.sps.TaskingResponse;
import org.vast.ows.sps.StatusReport.RequestStatus;
import org.vast.ows.sps.StatusReport.TaskStatus;

import com.deimos.sps.GetFeasibility.Operation;
import com.spotimage.eosps.EOReportHelper;
import com.spotimage.eosps.EOConstants.AcqStatus;
import com.spotimage.eosps.EOConstants.ReportType;

/**
 * The aim of this class is handle with the Database. performing operations such
 * as createTable, Drop all, Delete, addTask,etc.
 * 
 * @author Ramón Fernández Buján
 */

public class TaskController {
    private Session session = HibernateUtil.getSessionFactory().openSession();
    public static boolean inUse = false;

    public TaskController() {
    }

    /**
     * Creates the Table TASK into the database dropping it first. The aim of
     * this method was to make it easy the testing meanwhile the developing of
     * the app.In a final version id not expected leave it like that.
     * 
     * @param none
     */
    public boolean createTables(boolean delete) {
	boolean response = true;
	if (!session.isOpen())
	    session = HibernateUtil.getSessionFactory().openSession();
	session.beginTransaction();

	if (delete) {
	    try {
		SQLQuery query = session.createSQLQuery("DROP TABLE EVENT");
		query.executeUpdate();

	    } catch (HibernateException e) {
	    }
	    try {
		SQLQuery query = session.createSQLQuery("DROP TABLE TASK");
		query.executeUpdate();
	    } catch (HibernateException e) {
	    }
	    try {
		SQLQuery query = session.createSQLQuery("DROP TABLE SEGMENT");
		query.executeUpdate();
	    } catch (HibernateException e) {
	    }
	}

	try {
	    SQLQuery query = session.createSQLQuery("CREATE TABLE EVENT( " + "eventId int, " + "taskId VARCHAR(100), " + "requestStatus VARCHAR(50), " + "operation VARCHAR(50), " + "acquisitionSuccessDescription VARCHAR(100), " + "acquisitionSuccess BOOLEAN, " + "taskStatus VARCHAR(15), " + "description VARCHAR(50), " + "feasibilityStudy BOOLEAN, " + "beginDate TIMESTAMP, " + "endDate TIMESTAMP, " + "estimatedToc TIMESTAMP, " + "expirationDate TIMESTAMP, " + "requestParameters VARCHAR(7000)," + "maxCloud DOUBLE," + "responseParameters VARCHAR(7000)," + "updateDate TIMESTAMP)");
	    query.executeUpdate();
	} catch (HibernateException e) {
	    response = false;
	}
	session.getTransaction().commit();
	session.beginTransaction();

	try {
	    SQLQuery query = session.createSQLQuery("CREATE TABLE SEGMENT( " + "segmentId int, " + "taskId VARCHAR(100), " + "sensor VARCHAR(50), " + "acqStatus VARCHAR(50), " + "name VARCHAR(50), " + "beginDate TIMESTAMP, " + "endDate TIMESTAMP, " + "updateDate TIMESTAMP)");
	    query.executeUpdate();
	} catch (HibernateException e) {
	    response = false;
	}
	session.getTransaction().commit();
	session.beginTransaction();

	try {
	    SQLQuery query = session.createSQLQuery("CREATE TABLE TASK( " + "taskId VARCHAR(100), " + "sensorId VARCHAR(15), " + "serviceType VARCHAR(15), " + "serviceURL VARCHAR(15), " + "delay DOUBLE, " + "title VARCHAR(50))");
	    query.executeUpdate();
	} catch (HibernateException e) {
	    response = false;
	}
	session.getTransaction().commit();
	return response;
    }

    /**
     * Adds a item Task into the Table TASK by now the ServiceType & ServiceURL
     * are hard coded but is pending to argue
     * 
     * @param id
     *            means the TaskId which is read in the request
     * @param status
     *            means the status of the Task which is go be asked by getStatus
     *            service
     * @param feasibilityStudy
     *            indicates whether is feasible or not Task
     * @param sensorId
     */

    public boolean taskAvaiable(String taskId) {
	return getTask(taskId) != null;
    }

    public boolean sensorAvaiable(String taskId) {
	return getTask(taskId) != null;
    }

    public Task getTask(String taskId) {
	Task task = null;
	if (!session.isOpen())
	    session = HibernateUtil.getSessionFactory().openSession();
	session.beginTransaction();
	task = (Task) session.get(Task.class, taskId);
	// session.getTransaction().commit();
	return task;
    }

    @SuppressWarnings("unchecked")
    public List<Event> getEventsSince(String taskId, Date since) {
	List<Event> events = null;
	Event event = null;
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();

	    if (since != null) {
		events = session.createCriteria(Event.class).setFetchMode("task", FetchMode.JOIN).add(Restrictions.like("task.taskId", taskId)).add(Restrictions.ge("updateDate", since)).addOrder(Order.asc("updateDate")).list();
	    } else {
		events = new ArrayList<Event>();
		event = getLastEvent(taskId);
		if (event != null)
		    events.add(event);
	    }
	} catch (Exception ex) {
	    ex.printStackTrace();
	}

	return events;
    }

    @SuppressWarnings("unchecked")
    public List<Task> getTasksBySensor(String sensorId) {
	List<Task> tasks = null;
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();
	    tasks = session.createCriteria(Task.class).add(Restrictions.like("sensorId", sensorId)).list();
	    if (tasks.size() == 0)
		tasks = null;
	    session.getTransaction().commit();
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return tasks;
    }

    public Event getLastEvent(String taskId) {
	Event event = null;
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();
	    Date date = (Date) session.createCriteria(Event.class).setFetchMode("task", FetchMode.JOIN).add(Restrictions.like("task.taskId", taskId)).setProjection(Projections.projectionList().add(Projections.max("updateDate"))).uniqueResult();
	    event = (Event) session.createCriteria(Event.class).setFetchMode("task", FetchMode.JOIN).add(Restrictions.like("task.taskId", taskId)).add(Restrictions.eq("updateDate", date)).uniqueResult();
	    session.getTransaction().commit();
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return event;
    }

    public boolean insertTask(Task task) {
	boolean success = false;
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    if (task.getTaskId() == null || getTask(task.getTaskId()) == null) {
		session.beginTransaction();
		session.persist(task);
		session.getTransaction().commit();
		success = true;
	    }
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return success;
    }

    public boolean insertEvent(Event event) {
	boolean success = false;
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    else {
		session.close();
		session = HibernateUtil.getSessionFactory().openSession();
	    }
	    session.beginTransaction();
	    if (event.getEventId() == null)
		session.persist(event);
	    else
		session.update(event);
	    session.getTransaction().commit();
	    success = true;
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return success;
    }

    public boolean insertSegments(Set<Segment> segments, Task task) {
	boolean success = true;
	deleteAllSegment(task);
	for (Segment segment : segments) {
	    segment.setTask(task);
	    success = success & insertSegment(segment);
	}
	return success;
    }

    public boolean insertSegment(Segment segment) {
	boolean success = false;
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    else {
		session.close();
		session = HibernateUtil.getSessionFactory().openSession();
	    }
	    session.beginTransaction();
	    if (segment.getSegmentId() == null)
		session.persist(segment);
	    else
		session.update(segment);
	    session.getTransaction().commit();
	    success = true;
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return success;
    }

    public boolean removeEvent(Event event) {
	boolean success = false;
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    else {
		session.close();
		session = HibernateUtil.getSessionFactory().openSession();
	    }
	    session.beginTransaction();
	    session.delete(event);
	    session.getTransaction().commit();
	    success = true;
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return success;
    }

    /**
     * deleteAll keeps the Table completely empty
     */
    public void deleteAllTask() {
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();

	    SQLQuery query = session.createSQLQuery("DELETE FROM TASK");
	    query.executeUpdate();
	    session.getTransaction().commit();
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
    }

    public void deleteAllSegment(Task task) {
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();

	    SQLQuery query = session.createSQLQuery("DELETE FROM Segment where taskId like '" + task.getTaskId() + "'");
	    query.executeUpdate();
	    session.getTransaction().commit();
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
    }

    @SuppressWarnings("unchecked")
    public List<String> isSensorInUse(String sensorId, Date begin, Date end, String taskId) {
	String task = null;
	List<String> tasks = new ArrayList<String>();
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();

	    SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	    List list = session.createSQLQuery("Select taskId from Segment where " + "(sensor like '" + sensorId + "'" + " and (acqStatus like '" + AcqStatus.PLANNED + "' or acqStatus like '" + AcqStatus.POTENTIAL + "')" + " and (beginDate between '" + sdf.format(begin) + "' and '" + sdf.format(end) + "' " + "or endDate between '" + sdf.format(begin) + "' and '" + sdf.format(end) + "'))").list();

	    session.close();

	    for (Object o : list) {
		task = (String) o;
		Event event = validateStatus(task);
		if ((taskId == null || task.compareTo(taskId) != 0) && event != null && (((event.getTaskStatus() == TaskStatus.InExecution || event.getTaskStatus() == TaskStatus.Reserved) && event.getRequestStatus() == RequestStatus.Accepted) || (event.getRequestStatus() == RequestStatus.Accepted && event.getTaskStatus() == null)))
		    tasks.add(task);
	    }
	    return tasks;
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return null;
    }

    @SuppressWarnings("unchecked")
    public List<String> isSensorInUse(String sensorId, Operation operation, TaskingResponse response) throws OWSException {
	Sensor sensor = new Sensor(sensorId);
	List<String> tasks = new ArrayList<String>();
	EOReportHelper eohelper;
	if (Operation.STUDIED == operation || !sensor.isSyn())
	    eohelper = new EOReportHelper(response, ReportType.FEASIBILITY);
	else
	    eohelper = new EOReportHelper(response, ReportType.PROG_STATUS);
	for (int i = 0; i < eohelper.getNumSegments(); i++) {
	    eohelper.loadSegment(i);
	    tasks.addAll(this.isSensorInUse(sensorId, eohelper.getAcquisitionStart(), eohelper.getAcquisitionStop(), response.getReport().getTaskID()));
	}
	return tasks;
    }

    @SuppressWarnings("unchecked")
    public List<Segment> sensorsInUse(String sensorId, Date begin, Date end) {
	String taskId = null;
	Integer segmentId;
	List<Segment> segments = new ArrayList<Segment>();
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();

	    SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	    List list = session.createSQLQuery("Select taskId, segmentId from Segment where " + "(sensor like '" + sensorId + "'" + " and (acqStatus like '" + AcqStatus.PLANNED + "' or acqStatus like '" + AcqStatus.POTENTIAL + "')" + " and (beginDate between '" + sdf.format(begin) + "' and '" + sdf.format(end) + "' " + "or endDate between '" + sdf.format(begin) + "' and '" + sdf.format(end) + "'))").list();

	    session.close();

	    for (Object o : list) {
		Object[] row = (Object[]) o;
		taskId = (String) row[0];
		segmentId = Integer.parseInt(row[1].toString());
		validateSegments(taskId);
		Segment segment = getSegment(segmentId);
		if (segment.getAcqStatus() == AcqStatus.PLANNED || segment.getAcqStatus() == AcqStatus.POTENTIAL) {
		    segments.add(segment);
		}
	    }
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return segments;
    }

    public Segment getSegment(Integer segmentId) {
	session.beginTransaction();
	return (Segment) session.createQuery("from Segment where segmentId = " + segmentId).uniqueResult();
    }

    public Segment getSegment(String taskId, String name) {
	session.beginTransaction();
	return (Segment) session.createQuery("from Segment where task like '" + taskId + "' and name like '" + name + "'").uniqueResult();
    }

    @SuppressWarnings("unchecked")
    public List<Segment> getAllSegment() {
	session.beginTransaction();
	List<Segment> list = (List<Segment>) session.createQuery("from Segment").list();
	return list;
    }

    @SuppressWarnings("unchecked")
    public void validateAllStatus() {
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();

	    List list = session.createSQLQuery("select Task.taskId, sensorId from Task, (" + "select taskId, max(updateDate) date " + "from Event group by taskId) e " + "where " + "Task.taskId = e.taskId and " + "e.taskId in (" + "select taskId " + "from event " + "where date = updateDate and " + "e.taskId = Event.taskId" + " and " + "operation not like '" + Operation.UPDATED + "' and " + "operation not like '" + Operation.STUDIED + "' and " + " (Event.taskStatus like '" + TaskStatus.Reserved + "' or " + "Event.taskStatus like '" + TaskStatus.InExecution + "'or " + "Event.requestStatus like '" + RequestStatus.Accepted + "'))").list();

	    session.close();

	    for (Object o : list) {
		Object[] row = (Object[]) o;
		this.validateStatus(row[0].toString());
		this.validateSegments(row[0].toString());
	    }
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
    }

    public Event validateStatus(String taskId) {
	Event event = null;
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();
	    Date date = (Date) session.createCriteria(Event.class).setFetchMode("task", FetchMode.JOIN).add(Restrictions.like("task.taskId", taskId)).setProjection(Projections.projectionList().add(Projections.max("updateDate"))).uniqueResult();
	    event = (Event) session.createCriteria(Event.class).setFetchMode("task", FetchMode.JOIN).add(Restrictions.like("task.taskId", taskId)).add(Restrictions.eq("updateDate", date)).uniqueResult();
	    Date current = new DateTime();

	    if (event == null)
		return null;

	    if (event.getResponseParameters() == null) {
		this.removeEvent(event);
		return null;
	    }

	    if (event.getOperation() == Operation.UPDATED || event.getOperation() == Operation.STUDIED)
		return null;

	    if (event != null && event.getTaskStatus() != TaskStatus.InExecution && event.getEndDate() != null && event.getBeginDate() != null && event.getRequestStatus() == RequestStatus.Accepted && current.before(event.getEndDate()) && current.after(event.getBeginDate()) && event.getTaskStatus() != TaskStatus.Reserved) {
		event.setEventId(null);
		event.setUpdateDate(new Date());
		event.setTaskStatus(TaskStatus.InExecution);
		event.setDescription("Task in execution");
		System.out.println(event.getTask().getTaskId() + ": Task InExecution");
		//Notification.notifyReport(event);
		insertEvent(event);
		return event;
	    }

	    if (event != null && event.getEndDate() != null && event.getRequestStatus() != RequestStatus.Rejected && event.getEndDate() != null && event.getRequestStatus() != RequestStatus.Pending && (event.getTaskStatus() == TaskStatus.InExecution || event.getTaskStatus() == null) && event.getEndDate().before(current)) {
		this.validateSegments(taskId);
		event.setRequestStatus(null);
		if (!(event != null && event.getExpirationDate() != null && event.getTaskStatus() == TaskStatus.Reserved && event.getExpirationDate().before(current))) {
		    if (isSegmentsFailed(UtilsDeimos.readParams(event.getResponseParameters())) && !isTaskValidated(UtilsDeimos.readParams(event.getResponseParameters()))) {
			event.setTaskStatus(TaskStatus.Failed);
			event.setDescription(event.getAcquisitionSuccessDescription());
			System.out.println(event.getTask().getTaskId() + ": Task failed");
			Notification.notifyReport(event);
			insertEvent(event);
			return event;
		    } else if (isAllSegmentsCancelled(UtilsDeimos.readParams(event.getResponseParameters()))) {
			event.setTaskStatus(TaskStatus.Cancelled);
			event.setDescription(event.getAcquisitionSuccessDescription());
			System.out.println(event.getTask().getTaskId() + ": Task cancelled");
			Notification.notifyReport(event);
			insertEvent(event);
			return event;
		    }
		}
		event.setRequestStatus(null);
		event.setTaskStatus(TaskStatus.Completed);
		event.setDescription("Task completed successfully");
		event.setUpdateDate(new Date());
		System.out.println(event.getTask().getTaskId() + ": Task Completed");
		Notification.notifyReport(event);
		insertEvent(event);
		return event;
	    } else if (event != null && event.getRequestStatus() != RequestStatus.Rejected && event.getEndDate() != null && event.getEndDate() != null && event.getRequestStatus() != RequestStatus.Pending && (event.getTaskStatus() == TaskStatus.InExecution || event.getTaskStatus() == null) && !isTaskInCompleted(UtilsDeimos.readParams(event.getResponseParameters())) && (!this.isSegmentsFailed(UtilsDeimos.readParams(event.getResponseParameters())) || this.isTaskValidated(UtilsDeimos.readParams(event.getResponseParameters())))) {
		this.validateSegments(taskId);
		event.setEventId(null);
		event.setRequestStatus(null);
		event.setTaskStatus(TaskStatus.Completed);
		event.setDescription("Task completed successfully");
		event.setUpdateDate(new Date());
		System.out.println(event.getTask().getTaskId() + ": Task Completed");
		Notification.notifyReport(event);
		insertEvent(event);
		return event;
	    } 

	    if (event != null && event.getExpirationDate() != null && event.getRequestStatus() != RequestStatus.Rejected && event.getTaskStatus() == TaskStatus.Reserved && event.getExpirationDate().before(current)) {
		this.validateSegments(taskId);
		event.setEventId(null);
		event.setDescription("Task expired");
		event.setRequestStatus(null);
		event.setTaskStatus(TaskStatus.Expired);
		event.setUpdateDate(new Date());
		System.out.println(event.getTask().getTaskId() + ": Task Expired");
		Notification.notifyReport(event);
		insertEvent(event);
		return event;
	    }
	    
	    session.getTransaction().commit();
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return event;
    }

    public Event validateSegments(String taskId) {
	Event event = null;
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();
	    Date date = (Date) session.createCriteria(Event.class).setFetchMode("task", FetchMode.JOIN).add(Restrictions.like("task.taskId", taskId)).setProjection(Projections.projectionList().add(Projections.max("updateDate"))).uniqueResult();
	    event = (Event) session.createCriteria(Event.class).setFetchMode("task", FetchMode.JOIN).add(Restrictions.like("task.taskId", taskId)).add(Restrictions.eq("updateDate", date)).uniqueResult();
	    session.getTransaction().commit();

	    if (event == null)
		return null;

	    String newSegments = replaceSegments(event.getResponseParameters(), (setSegmentsStatus(UtilsDeimos.readParams(event.getResponseParameters()), event)));
	    if (newSegments != null) {
		if (!newSegments.contains(event.getDescription()))
		    event.setDescription(newSegments.split("description")[1].split(">")[1].split("<")[0]);
		event.setResponseParameters(newSegments);
		// notificar actualización

		event.setEventId(null);
		event.setUpdateDate(new Date());
		insertEvent(event);
	    }

	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return event;
    }

    public String replaceSegments(String params, String newParams) {
	if (params == null || newParams == null)
	    return null;
	String newResponse = null;
	String paramsType = "", newParamsType = "";
	if (params.contains("FeasibilityStudy"))
	    paramsType = "FeasibilityStudy";
	else
	    paramsType = "ProgrammingStatus";

	if (newParams.contains("FeasibilityStudy"))
	    newParamsType = "FeasibilityStudy";
	else
	    newParamsType = "ProgrammingStatus";

	String[] splitparams = params.split(paramsType);
	String[] splitnewParams = newParams.split(newParamsType);
	if (splitparams.length == 3 && splitnewParams.length == 3 && splitnewParams[1].compareTo(splitparams[1]) != 0) {
	    newResponse = splitparams[0] + paramsType + splitnewParams[1] + paramsType + splitparams[2];
	}

	if (newResponse != null)
	    splitparams = newResponse.split("description");
	else
	    splitparams = params.split("description");
	splitnewParams = newParams.split("description");
	if (splitparams.length == 3 && splitnewParams.length == 3 && splitnewParams[1].compareTo(splitparams[1]) != 0) {
	    newResponse = splitparams[0] + "description" + splitnewParams[1] + "description" + splitparams[2];
	}

	return newResponse;
    }

    @SuppressWarnings( { "unchecked", "unused" })
    private boolean isSegmentsActive(TaskingResponse response) {
	StatusReport report = response.getReport();
	EOReportHelper eohelper = new EOReportHelper(report);
	for (int i = 0; i < eohelper.getNumSegments(); i++) {
	    eohelper.loadSegment(i);
	    if (eohelper.getObjectStatus() != AcqStatus.CANCELLED && eohelper.getObjectStatus() != AcqStatus.FAILED && eohelper.getObjectStatus() != AcqStatus.REJECTED)
		return true;
	}
	return false;
    }
    
    @SuppressWarnings("unchecked")
    private boolean isTaskValidated(TaskingResponse response) {
	StatusReport report = response.getReport();
	EOReportHelper eohelper = new EOReportHelper(report);
	for (int i = 0; eohelper.getReportType() != null && i < eohelper.getNumSegments(); i++) {
	    eohelper.loadSegment(i);
	    if (eohelper.getObjectStatus() == AcqStatus.VALIDATED)
		return true;
	}
	return false;
    }

    @SuppressWarnings("unchecked")
    private boolean isTaskInCompleted(TaskingResponse response) {
	StatusReport report = response.getReport();
	EOReportHelper eohelper = new EOReportHelper(report);
	for (int i = 0; eohelper.getReportType() != null && i < eohelper.getNumSegments(); i++) {
	    eohelper.loadSegment(i);
	    if (eohelper.getObjectStatus() != AcqStatus.CANCELLED && eohelper.getObjectStatus() != AcqStatus.ACQUIRED && eohelper.getObjectStatus() != AcqStatus.FAILED && eohelper.getObjectStatus() != AcqStatus.REJECTED && eohelper.getObjectStatus() != AcqStatus.VALIDATED)
		return true;
	}
	return false;
    }

    @SuppressWarnings( { "unchecked" })
    public boolean isSegmentsFailed(TaskingResponse response) {
	StatusReport report = response.getReport();
	EOReportHelper eohelper = new EOReportHelper(report);
	for (int i = 0; i < eohelper.getNumSegments(); i++) {
	    eohelper.loadSegment(i);
	    if (eohelper.getObjectStatus() == AcqStatus.FAILED || eohelper.getObjectStatus() == AcqStatus.REJECTED)
		return true;
	}
	return false;
    }

    @SuppressWarnings( { "unchecked" })
    public boolean isAllSegmentsCancelled(TaskingResponse response) {
	StatusReport report = response.getReport();
	EOReportHelper eohelper = new EOReportHelper(report);
	for (int i = 0; i < eohelper.getNumSegments(); i++) {
	    eohelper.loadSegment(i);
	    if (eohelper.getObjectStatus() == AcqStatus.CANCELLED)
		return true;
	}
	return false;
    }

    @SuppressWarnings("unchecked")
    private String setSegmentsStatus(TaskingResponse response, Event event) {
	boolean notifyAcquired = false;
	boolean notifyCancelled = false;
	boolean notifyPlanned = false;
	boolean notifyFailed = false;
	String original = UtilsDeimos.getParameters(response);
	String description = "";

	try {
	    int acquired = 0;
	    StatusReport report = response.getReport();
	    if (report.getExtensions() == null)
		return null;
	    EOReportHelper eohelper = new EOReportHelper(report);
	    ScenarioResponse availabilityResponse = Scenario.getAvailability(eohelper, report, event.getMaxCloud());
	    if (eohelper.getReportType() == null)
		return null;
	    for (int i = 0; i < eohelper.getNumSegments(); i++) {
		eohelper.loadSegment(i);
		Date segStart;
		Date segStop;
		try {
		    segStart = UtilsDeimos.sdf_hma.parse(eohelper.getAcquisitionStart().formatIso(0));
		    segStop = UtilsDeimos.sdf_hma.parse(eohelper.getAcquisitionStop().formatIso(0));
		} catch (ParseException e) {
		    // TODO Auto-generated catch block
		    return null;
		}
		availabilityResponse = Scenario.getSegmentAvailability(eohelper, report, event.getMaxCloud());
		description = description + availabilityResponse.getDescription();
		if (eohelper.getObjectStatus() == AcqStatus.POTENTIAL || eohelper.getObjectStatus() == AcqStatus.PLANNED) {
		    if (availabilityResponse != null && !availabilityResponse.isAvailable()) {
			eohelper.setObjectStatus(AcqStatus.FAILED);
			System.out.println(new Date() + " - " + eohelper.getID() + ": segment FAILED");
			notifyFailed = true;
		    }

		    if (eohelper.getObjectStatus() == AcqStatus.POTENTIAL || eohelper.getObjectStatus() == AcqStatus.PLANNED) {
			if (event.getTaskStatus() == TaskStatus.Completed) {
			    eohelper.setObjectStatus(AcqStatus.ACQUIRED);
			    System.out.println(new Date() + " - " + eohelper.getID() + ": segment ACQUIRED");
			    notifyAcquired = true;
			    acquired++;
			}

			if (event.getTaskStatus() == TaskStatus.InExecution) {
			    if (new Date().after(segStart) && new Date().before(segStop) && eohelper.getObjectStatus() != AcqStatus.PLANNED) {
				eohelper.setObjectStatus(AcqStatus.PLANNED);
				System.out.println(new Date() + " - " + eohelper.getID() + ": segment PLANNED");
				notifyPlanned = true;
			    } else if (new Date().after(segStop) && eohelper.getObjectStatus() != AcqStatus.ACQUIRED) {
				eohelper.setObjectStatus(AcqStatus.ACQUIRED);
				System.out.println(new Date() + " - " + eohelper.getID() + ": segment ACQUIRED");
				notifyAcquired = true;
				acquired++;
			    }
			}

			if (event.getTaskStatus() == TaskStatus.Expired) {
			    if (eohelper.getObjectStatus() == AcqStatus.PLANNED || eohelper.getObjectStatus() == AcqStatus.POTENTIAL) {
				eohelper.setObjectStatus(AcqStatus.CANCELLED);
				System.out.println(new Date() + " - " + eohelper.getID() + ": segment CANCELLED");
				notifyCancelled = true;
			    }
			}

			if (event.getRequestStatus() == RequestStatus.Rejected && (eohelper.getObjectStatus() == AcqStatus.PLANNED)) {
			    eohelper.setObjectStatus(AcqStatus.REJECTED);
			    System.out.println(new Date() + " - " + eohelper.getID() + ": segment REJECTED");
			    notifyFailed = true;
			}
			if (event.getTaskStatus() == TaskStatus.Cancelled && (eohelper.getObjectStatus() == AcqStatus.PLANNED || eohelper.getObjectStatus() == AcqStatus.POTENTIAL)) {
			    eohelper.setObjectStatus(AcqStatus.CANCELLED);
			    System.out.println(new Date() + " - " + eohelper.getID() + ": segment CANCELLED");
			    notifyCancelled = true;
			}
			if (event.getTaskStatus() == TaskStatus.Failed && (eohelper.getObjectStatus() == AcqStatus.PLANNED || eohelper.getObjectStatus() == AcqStatus.POTENTIAL)) {
			    eohelper.setObjectStatus(AcqStatus.FAILED);
			    System.out.println(new Date() + " - " + eohelper.getID() + ": segment FAILED");
			    notifyCancelled = true;
			}
		    }
		}

		if (eohelper.getObjectStatus() == AcqStatus.ACQUIRED)
		    acquired++;
		Segment segment = getSegment(event.getTask().getTaskId(), eohelper.getID());
		if (segment != null && segment.getAcqStatus() != eohelper.getObjectStatus()) {
		    segment.setAcqStatus(eohelper.getObjectStatus());
		    segment.setUpdateDate(new Date());
		    insertSegment(segment);
		}
	    }

	    eohelper.writeReportInfo();

	    if (eohelper.getNumSegments() > 0 && acquired != 0)
		report.setPercentCompletion((100 * acquired) / eohelper.getNumSegments());

	    if (original.compareTo(UtilsDeimos.getParameters(response)) != 0) {
		report.setDescription(description);
	    } else
		return null;

	    report.touch();
	    if (notifyAcquired && Notification.getInstance() != null)
		Notification.getInstance().notifySegmentAcquired(report);
	    if (notifyCancelled && Notification.getInstance() != null)
		Notification.getInstance().notifySegmentCancelled(report);
	    if (notifyPlanned && Notification.getInstance() != null)
		Notification.getInstance().notifySegmentPlanned(report);
	    if (notifyFailed && Notification.getInstance() != null)
		Notification.getInstance().notifySegmentFailed(report);

	    return UtilsDeimos.getParameters(response);
	} catch (Exception e) {
	    e.printStackTrace();
	}
	return null;
    }

    @SuppressWarnings("unchecked")
    public String purge() {
	String response = "";
	try {
	    if (!session.isOpen())
		session = HibernateUtil.getSessionFactory().openSession();
	    session.beginTransaction();

	    List list = session.createSQLQuery("select eventId, requestStatus, Event.taskId " + "from " + "Event, " + "(select taskId, max(updateDate) date " + "from Event group by taskId) e " + "where " + "e.taskId = event.taskId and " + "event.eventId in (" + "Select eventId " + "from event " + "where " + "date = updateDate and " + "e.taskId = Event.taskId and " + "Event.requestStatus like 'PENDING'" + ")").list();

	    for (Object o : list) {
		Object[] row = (Object[]) o;
		session.createQuery("delete from Event event where eventId = " + row[0].toString()).executeUpdate();
		response = "Deleting " + row[0].toString() + " " + row[1].toString() + " " + row[2].toString() + "\n";
	    }
	    int count = session.createQuery("delete from Event event where event.task.taskId is NULL").executeUpdate();
	    response = response + count + " null events deleted\n";
	    count = session.createQuery("delete from Task task where task not in (select event.task from Event event)").executeUpdate();
	    response = response + count + " orphans tasks deleted\n";
	    session.getTransaction().commit();
	    session.close();
	} catch (Exception ex) {
	    ex.printStackTrace();
	}
	return response;
    }

}
